﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Timers;
using System.Media;
using System.Windows.Media.Animation;
using com.skype.api;
using System.Threading;
using System.Diagnostics;
using Hugo.UIPages;
using Hugo.UIOptions;

namespace Hugo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Label dayLabel;
        Label timeLabel;

        Boolean isSleeping;
        Boolean useHandCursor = true;

        HandCursor cursor;

        int sleepTimerAmount = 1000 * 30; // 30 seconds

        public Canvas mainCanvas { get; set; }

        static Queue<NotificationUIPage> notificationQueue = new Queue<NotificationUIPage>();

        static Stack<UIPage> pageStack = new Stack<UIPage>();
        static UIPage root;
        static UIPage inbox;
        static UIPage help;
        static UIPage screenSaver;

        private static Action EmptyDelegate = delegate() { };

        private static MainWindow instance;

        public static MainWindow getInstance()
        {
            return instance;
        }

        public MainWindow()
        {
            if (instance == null)
            {
                instance = this;
            }

            InitializeComponent();
            init();

            //new Hugo.Gesture.GestureTranslator(this);
            //GestureWindow gw = new GestureWindow();
            //gw.Show();

            restartSleepTimer();

            if (useHandCursor)
            {
                cursor = new HandCursor(mainCanvas);

                    DispatcherTimer updateHandCursorTimer = new DispatcherTimer();
                    updateHandCursorTimer.Interval = TimeSpan.FromMilliseconds(100);
                    updateHandCursorTimer.Tick += new EventHandler(updateHandCursorTimerTick);
                    updateHandCursorTimer.Start();
            }
        }

        System.Windows.Point lastCursor;

        private void updateHandCursorTimerTick(Object sender, EventArgs e)
        {

            System.Windows.Point p = cursor.getPosition();

            if (lastCursor != null && Math.Max(p.X - lastCursor.X, p.Y - lastCursor.Y) > 10)
            {
                wakeUp();
                restartSleepTimer();
            }

            lastCursor = p;

            if (!isSleeping)
            {
                this.currentPage().setCursorPosition(p);
            }
        }

        private void init()
        {

            initCanvases();

            Rectangle bg = Util.getSymbol(
                Util.loadBitmap(GlobalSettings.Background), 100, 100
                );
            bg.Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
            bg.Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
            mainCanvas.Children.Add(bg);
            Canvas.SetLeft(bg, 0);
            Canvas.SetTop(bg, 0);


            initTime();
            initPages();

            if (GlobalSettings.isUsingSkype)
            {
                Communicate.getInstance();
            }


            
        }

        private void sleep()
        {
            if (!isSleeping)
            {
                // unset page
                this.currentPage().unSetPage();
                screenSaver.setPage();

                // fade out hand
                cursor.fadeOut();
            }
            isSleeping = true;
        }

        private void wakeUp()
        {
            if (isSleeping)
            {
                this.currentPage().setPage();
                screenSaver.unSetPage();

                cursor.fadeIn();
            }
            isSleeping = false;
        }

        DispatcherTimer sleepTimer;

        private void restartSleepTimer()
        {
            if (sleepTimer != null)
            {
                sleepTimer.Stop();
                sleepTimer.Start();
            }
            else
            {
                sleepTimer = new DispatcherTimer();
                sleepTimer.Interval = TimeSpan.FromMilliseconds(sleepTimerAmount);
                sleepTimer.Tick += new EventHandler(sleepTimerTick);
                sleepTimer.Start();
            }
        }

        private void sleepTimerTick(Object sender, EventArgs e)
        {
            sleepTimer.Stop();
            sleep();
        }

        private void initCanvases()
        {
            mainCanvas = new Canvas();
            mainCanvas.Name = "mainCanvas";

            this.Content = mainCanvas;
        }



        private void initTime()
        {
            Rectangle r = new Rectangle();
            r.Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
            r.Height = 120;
            mainCanvas.Children.Add(r);
            r.Fill = new SolidColorBrush(GlobalSettings.BannerColor);
            //r.Opacity = 0.8;

            Canvas.SetTop(r, 0);
            Canvas.SetLeft(r, 0);

            dayLabel = new Label();
            mainCanvas.Children.Add(dayLabel);
            Canvas.SetTop(dayLabel, -10);

            dayLabel.Foreground = new SolidColorBrush(GlobalSettings.TextColor);
            dayLabel.FontSize = 40;

            timeLabel = new Label();
            mainCanvas.Children.Add(timeLabel);
            Canvas.SetTop(timeLabel, 25);

            timeLabel.Foreground = new SolidColorBrush(GlobalSettings.TextColor);
            timeLabel.FontSize = 70;

            DispatcherTimer timeTimer = new DispatcherTimer();
            timeTimer.Interval = TimeSpan.FromSeconds(1);
            timeTimer.Tick += new EventHandler(updateTime);
            timeTimer.Start();
        }

        public void updateTime(Object sender, EventArgs e)
        {

            //Canvas.SetLeft(ellipseC, contentCanvas.ActualWidth / 2 - ellipseC.Width / 2);
            //Canvas.SetTop(ellipseC, contentCanvas.ActualHeight / 2 - ellipseC.Height / 2);
            //Canvas.SetZIndex(ellipseC, 100);

            //timeLabel.Visibility = System.Windows.Visibility.Hidden;

            DateTime dateValue = DateTime.Now;
            // Console.WriteLine(dateValue.ToString("dddd"));    // Displays Wed

            this.dayLabel.Content = dateValue.ToString("dddd MMMM d");//DateTime.Now.ToLocalTime();
            this.timeLabel.Content = dateValue.ToString("h:mm tt");
            // need to rerender to get updated width
            dayLabel.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
            timeLabel.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
            Canvas.SetLeft(dayLabel, System.Windows.SystemParameters.PrimaryScreenWidth / 2 - dayLabel.ActualWidth / 2);
            Canvas.SetLeft(timeLabel, System.Windows.SystemParameters.PrimaryScreenWidth / 2 - timeLabel.ActualWidth / 2);
            // timeLabel.Visibility = System.Windows.Visibility.Visible;

        }

        private void initPages()
        {
            Console.WriteLine(Properties.Resources.ResourceManager.BaseName);

            screenSaver = new ScreenSaverUIPage();

            TileUIPage rootPage = new TileUIPage("Home", null);
            TileUIPage skypePage = new TileUIPage("Communicate", Util.loadBitmap(Properties.Resources.icon_skype2));
            TileUIPage entertainPage = new TileUIPage("Entertainment", Util.loadBitmap(Properties.Resources.icon_tv2));
            TileUIPage newsPage = new TileUIPage("News", Util.loadBitmap(Properties.Resources.icon_info));

            inbox = new InboxUIPage();

            //rootPage.setNavigationComponentsVisible(false);

            SkypeMessageListUI helpPage = new SkypeMessageListUI("Call Nurse", GlobalSettings.nurseSkypeID, SkypeMessageListUI.getStandardHelpOptions(), Util.loadBitmap(Properties.Resources.icon_skypecontact));

            help = helpPage;

            SkypeContactListUI videoChatPage = new SkypeContactListUI("Call", Util.loadBitmap(Properties.Resources.icon_skypecontact), Hugo.UIPages.SkypeContactListUI.SkypeAction.Call);
            SkypeContactListUI textChatPage = new SkypeContactListUI("Text", Util.loadBitmap(Properties.Resources.icon_skypecontact), Hugo.UIPages.SkypeContactListUI.SkypeAction.Message);

            textChatPage.addMessageOptions(SkypeMessageListUI.getStandardMessageOptions());

            skypePage.addUIOption(videoChatPage);
            skypePage.addUIOption(textChatPage);

            rootPage.addUIOption(inbox);
            rootPage.addUIOption(skypePage);
            //rootPage.addUIOption(entertainPage);
            //rootPage.addUIOption(newsPage);

            root = rootPage;

            pushPage(root);

        }

        static NotificationUIPage currentNotification = null;

        /// Events
        /// 
        public void respondToKey(object sender, KeyEventArgs e)
        {
            if (this.isSleeping)
            {
                wakeUp();
                return;
            }
            else
            {
                restartSleepTimer();
            }

            if (e.Key == Key.H)
            {
                pushPage(help);
                return;
            }
            if (e.Key == Key.N)
            {
                //if (currentNotification == null)
                //{
                List<UIOption> options = new List<UIOption>();
                options.Add(new TileUIPage("SkypeCall", Hugo.Util.loadBitmap(Properties.Resources.icon_left)));
                // should pass a function or event handler
                NotificationUIPage p = new NotificationUIPage("Andrea sent you a message", "Incoming call from blah. Incoming call from blah. Incoming call from blah. Incoming call from blah. Incoming call from blah. Incoming call from blah. ", options);
                enqueueNotification(p);
                //}
                //else
                //{
                //    popCurrentNotification;
                //}
            }
            else
            {
                if (notificationQueue.Count > 0)
                {
                    notificationQueue.Peek().respondToKey(e);
                }
                else
                {
                    Console.WriteLine("Sending " + e.Key + " to " + currentPage().Name);
                    currentPage().respondToKey(e);
                }
            }
        }

        /// Page Control
        /// 
        static int notificationTimeout = 3000;

        public static void enqueueNotification(NotificationUIPage p)
        {
            Sounds.playSound(Sounds.Sound.Notification);
            notificationQueue.Enqueue(p);

            showNextNotificationIfPossible();
        }

        private static void showNextNotificationIfPossible()
        {
            if (currentNotification != null || notificationQueue.Count == 0) { return; }

            currentNotification = notificationQueue.Peek();

            NotificationUIPage p = currentNotification;
            p.setPage();

            DispatcherTimer _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromMilliseconds(notificationTimeout);
            _timer.Tick += new EventHandler(notificationTimerElapsed);
            _timer.Start();
        }

        static void notificationTimerElapsed(object sender, EventArgs e)
        {
            //we want this event handler executed just once
            DispatcherTimer thisTimer = (DispatcherTimer)sender;
            thisTimer.Stop();

            dequeueCurrentNotification();
        }

        private static void dequeueCurrentNotification()
        {
            if (currentNotification == null) { return; }

            currentNotification.unSetPage();
            notificationQueue.Dequeue();

            currentNotification = null;
            showNextNotificationIfPossible();
        }

        internal static void pushPage(UIPage p)
        {
            if (pageStack.Count > 0)
            {
                pageStack.Peek().unSetPage();
            }
           
            pageStack.Push(p);
            p.setPage();

            if (GlobalSettings.isBlind)
            {
                Sounds.speakMessageAsync(p.Name);
            }
            else
            {
                Sounds.playSound(Sounds.Sound.Navigate);
            }
            //Sounds.speakMessage(p.Name);
        }

        internal static void popAllPages()
        {
            pageStack.Peek().unSetPage();

            while (pageStack.Peek() != root)
            {
                pageStack.Pop();
            }

            root.setPage();
        }

        internal static void popPage()
        {
            if (pageStack.Count == 1)
            {
                Console.WriteLine("Can't leave the root");
                return;
            }

            Console.WriteLine("Leaving page " + pageStack.Peek().Name);
            pageStack.Pop().unSetPage();

            Console.WriteLine("Reshowing page " + pageStack.Peek().Name);
            pageStack.Peek().setPage();


            if (GlobalSettings.isBlind)
            {
                Sounds.speakMessageAsync(pageStack.Peek().Name);
            }
            else
            {
                Sounds.playSound(Sounds.Sound.Navigate);
            }
            
        }

        private UIPage currentPage()
        {
            return pageStack.Peek();
        }

        internal static void showInbox()
        {
            pushPage(inbox);
        }

        internal static void callNurse()
        {
            pushPage(help);
        }
    }
}
